package com.tianji.learning.task;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.constants.CacheConstant;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.learning.domain.Vo.PointsBoardItemVO;
import com.tianji.learning.domain.po.PointsBoardSeason;
import com.tianji.learning.mapper.PointsBoardMapper;
import com.tianji.learning.service.IPointsBoardSeasonService;
import com.tianji.learning.service.UserQueryService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.tianji.common.constants.Constant.POINTS_BOARD_PREFIX;

@Component
@Slf4j
@RequiredArgsConstructor
public class PointsBoardSyncToMysqlTask {

    @Autowired
    private IPointsBoardSeasonService seasonService;
    @Autowired
    private PointsBoardMapper boardMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private UserQueryService userQueryService;

    // 每个月1号凌晨1点，把redis中的zset中的榜单数据同步到mysql
    // 秒 分 时 天 月 周
    @Scheduled(cron = "0 0 1 1 * ?")
    public void pointsBoardSyncToMysql(){
        // 根据赛季的开始时间和结束时间查询赛季的id，上一个月的开始时间和结束时间
        LocalDate localDate = LocalDateTime.now().minusMonths(1).toLocalDate();
        LocalDate beginDate = DateUtils.getMonthBegin(localDate);
        LocalDate endDate = DateUtils.getMonthEnd(localDate);
        PointsBoardSeason season = seasonService.getByDate(beginDate, endDate);
        if(season == null){
            log.error("没有更多赛季");
            return;
        }
        // 生成mysql中的表名：points_board_${赛季的id}
        Integer id = season.getId();
        String tableName = POINTS_BOARD_PREFIX + id;
        boardMapper.createTable(tableName);
        // 分页读取redis中的zset中的排行榜
        String yyyyMM = LocalDateTimeUtil.format(localDate, "yyyyMM");
        String key = CacheConstant.POINTS_BOARD+yyyyMM;
        int pageNo = 1, pageSize = 100;
        while(true){
            // 起始索引,每页10，  1页0，2页10，3页20
            int start = (pageNo-1)*pageSize;
            // 结束索引，每页10，  1页10-1，2页20-1，3页30-1
            int end = (pageNo)*pageSize - 1;
            Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
            if(CollUtils.isEmpty(typedTuples)){
                break;
            }
            List<PointsBoardItemVO> voList = new ArrayList<>();
            ArrayList<ZSetOperations.TypedTuple<String>> tupleList = new ArrayList<>(typedTuples);
            for (int i =0; i<tupleList.size(); i++) {
                ZSetOperations.TypedTuple<String> typedTuple = tupleList.get(i);
                Double userScore = typedTuple.getScore();
                String userIdstring = typedTuple.getValue();
                PointsBoardItemVO itemVO = new PointsBoardItemVO();
                itemVO.setUserId(Long.parseLong(userIdstring));
                itemVO.setName(userIdstring);
                itemVO.setRank(start + i + 1);//根据索引，计算排名
                itemVO.setPoints(userScore.intValue());
                voList.add(itemVO);
            }
            // userId -> userName
            Map<Long, UserDTO> userMap = userQueryService.queryUserMap(voList);
            for (PointsBoardItemVO itemVO : voList) {
                UserDTO userDTO = userMap.get(itemVO.getUserId());
                itemVO.setName(userDTO==null?"":userDTO.getName());
            }
            // 批量写入mysql
            boardMapper.batchInsert(tableName, voList);
            // 下一页
            pageNo++;
        }
        // 删除redis中的榜单数据
        redisTemplate.unlink(key);
    }

    @XxlJob("createTableHandle")
    public ReturnT<String> createTableHandle(){
        // 根据赛季的开始时间和结束时间查询赛季的id，上一个月的开始时间和结束时间
        LocalDate localDate = LocalDateTime.now().minusMonths(1).toLocalDate();
        LocalDate beginDate = DateUtils.getMonthBegin(localDate);
        LocalDate endDate = DateUtils.getMonthEnd(localDate);
        PointsBoardSeason season = seasonService.getByDate(beginDate, endDate);
        if(season == null){
            log.error("没有更多赛季");
            XxlJobHelper.log("没有更多赛季");
            return ReturnT.FAIL;
        }
        // 生成mysql中的表名：points_board_${赛季的id}
        Integer id = season.getId();
        String tableName = POINTS_BOARD_PREFIX + id;
        boardMapper.createTable(tableName);
        return ReturnT.SUCCESS;
    }

    @XxlJob("syncRedisToMysql")
    public ReturnT<String> syncRedisToMysql(){
        return ReturnT.SUCCESS;
    }

    @XxlJob("cleanRedisBoardTask")
    public ReturnT<String> cleanRedisBoardTask(){
        return ReturnT.SUCCESS;
    }
}